package controllers

import java.io.File
import javax.inject.Inject

import models.Tables._
import org.apache.commons.io.FileUtils
import play.api.mvc._
import dao._
import utils.Utils

import scala.collection.JavaConverters._
import scala.concurrent.{Await, Future}
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration.Duration
import implicits.Implicits._

class DataInsertController @Inject()(cc: ControllerComponents, bgAnnoDao: BgAnnoDao, bgCdsDao: BgCdsDao, bgPepDao: BgPepDao, indelDao: IndelDao,
                                     ssrDao: SsrDao, paperDao: PaperDao, literatureDao: LiteratureDao, melonShapeDao: MelonShapeDao,
                                     sampleDao: SampleDao, geneticMapDao: GeneticMapDao, genotypeDao: GenotypeDao,
                                     qtlDao: QtlDao, fpkmDao: FpkmDao, umamiDao: UmamiDao, umamiSiteDao: UmamiSiteDao,
                                     bitterTasteDao: BitterTasteDao, mrnaDao: GeneDao) extends AbstractController(cc) {

  val parent = new File("C:\\cbgd_database\\test")

  def insertBgAnno = Action.async {
    val file = new File(parent, "BG_Anno.txt")
    val buffer = FileUtils.readLines(file).asScala.drop(1).toList
    val rows = buffer.map { x =>
      val columns = x.split("\t").map { y =>
        y.replaceAll("^\"", "").replaceAll("\"$", "")
      }
      BgannoRow(columns(0), columns(1), columns(2).toInt, columns(3).toInt, columns(4), columns(5), columns(6), columns(7),
        columns(8), columns(9), columns(10), columns(11), columns(12), columns(13), columns(14))
    }
    bgAnnoDao.deleteAll.flatMap(_ => bgAnnoDao.insertAll(rows)).map { x =>
      Ok("success!")
    }
    //    bgAnnoDao.deleteAll.map { x =>
    //      Ok("success!")
    //    }
  }

  def insertBgCds = Action.async {
    val file = new File(parent, "BottleGourd.gene.cds.final")
    val buffer = FileUtils.readLines(file).asScala.toList
    val idsBuffer = buffer.filter(_.startsWith((">")))
    val cdsBuffer = buffer.filterNot(_.startsWith((">")))
    val rows = idsBuffer.zip(cdsBuffer).map {
      case (ids, cds) =>
        val id = ids.split("\\s+")(0).replaceAll("^>", "")
        BgcdsRow(id, cds)
    }

    bgCdsDao.deleteAll.flatMap(_ => bgCdsDao.insertAll(rows)).map { x =>
      Ok("success!")
    }
  }

  def insertMrna = Action {
    println("in")

    val startTime = System.currentTimeMillis()

    val gffFile = new File(parent, "BottleGourd.gene.gff")
    val gffLines = FileUtils.readLines(gffFile).asScala
    case class RegionData(geneId: String, chr: String, start: Int, end: Int, dir: String)
    val regions = gffLines.filter(_.split("\t")(2) == "mRNA").map { line =>
      val columns = line.split("\t")
      val id = columns(8).init.split("=")(1)
      RegionData(id, columns(0), columns(3).toInt, columns(4).toInt, columns(6))
    }
    val faFile = new File(parent, "H-PB-GapClose.fa")
    val geneBuffer = FileUtils.readLines(faFile).asScala.toList
    val idsBuffer = geneBuffer.filter(_.startsWith((">")))
    val seqBuffer = geneBuffer.filterNot(_.startsWith((">")))
    val geneMap = idsBuffer.zip(seqBuffer).map {
      case (ids, seq) =>
        val id = ids.split("\\s+")(0).replaceAll("^>", "")
        (id, seq)
    }.toMap

    val seqHash = Map('A' -> 'T', 'T' -> 'A', 'C' -> 'G', 'G' -> 'C', 'N' -> 'N')
    val rows = regions.map { region =>
      val seq = geneMap(region.chr).slice(region.start - 1, region.end)
      val trueSeq = if (region.dir == "-") {
        seq.reverse.map(seqHash(_))
      } else seq
      GeneRow(region.geneId, trueSeq)
    }

    println("read line successfully!" + Utils.getTime(startTime))

    Utils.execFuture(mrnaDao.deleteAll)
    val rowsSize = rows.size
    val num = 2000
    var index = 0

    rows.grouped(num).foreach { x =>
      Await.result(mrnaDao.insertAll(x.toList), Duration.Inf)
      index = index + 1
      val percent = if ((index * num * 100) / rowsSize >= 100) "100%" else (index * num * 100) / rowsSize + "%"
      println(percent + "\t" + Utils.getTime(startTime))
    }
    println("insert table successfully!" + Utils.getTime(startTime))
    Ok("success!")
  }

  def insertIndel = Action.async {
    val file = new File(parent, "indel.txt")
    val lines = file.txtLines
    val rows = lines.map { columns =>
      IndelRow(columns(0), columns(1).toInt, columns(2), columns(3), columns(4).toInt, columns(5), columns(6))
    }
    indelDao.deleteAll.flatMap(_ => indelDao.insertAll(rows)).map { x =>
      Ok("success!")
    }
  }

  def insertGenotype = Action {
    val startTime = System.currentTimeMillis()
    val file = new File(parent, "genotype_1.txt")
    val lines = file.txtLines
    val rows = lines.map { columns =>
      GenotypeRow(columns(0), columns(1), columns(2))
    }
    println("read line successfully!" + Utils.getTime(startTime))
    val rowsSize = rows.size
    val num = 50000
    var index = 0
    rows.grouped(num).foreach { x =>
      Await.result(genotypeDao.insertAll(x), Duration.Inf)
      index = index + 1
      val percent = if ((index * num * 100) / rowsSize >= 100) "100%" else (index * num * 100) / rowsSize + "%"
      println(percent + "\t" + Utils.getTime(startTime))
    }
    println("insert table successfully!" + Utils.getTime(startTime))
    Ok("success!")
  }

  def insertLiteratures = Action.async {
    val file=new File(parent,"literature.xlsx")
    val lines =file.xlsxLines().drop(1)
    val rows = lines.map { columns =>
      LiteratureRow(0, columns(1), columns(2), columns(3), columns(4), columns(5))
    }
    literatureDao.deleteAll.flatMap(_ => literatureDao.insertAll(rows.toList)).map { x =>
      Ok("success!")
    }
  }

  def insertMelonShape = Action.async {
    val file = new File(parent, "melonshape.txt")
    val lines = file.txtLines
    val rows = lines.map { columns =>
      MelonshapeRow(0, columns(1), columns(2), columns(3), columns(4), columns(5))
    }
    melonShapeDao.deleteAll.flatMap(_ => melonShapeDao.insertAll(rows)).map { x =>
      Ok("success!")
    }
  }

  def insertSamples = Action.async {
    val file=new File(parent,"sample.txt")
    val lines =file.txtLines
    val rows = lines.map { tmpColumns =>
      val columns=tmpColumns.padTo(3,"")
      SampleRow(0, columns(1), columns(2))
    }
    sampleDao.deleteAll.flatMap(_ => sampleDao.insertAll(rows)).map { x =>
      Ok("success!")
    }
  }

  def insertSsr = Action.async {
    val file = new File(parent, "ssr.txt")
    val lines = file.txtLines
    val rows = lines.map { columns =>
      SsrRow(columns(0), columns(1), columns(2), columns(3).toInt, columns(4), columns(5), columns(6), columns(7))
    }
    ssrDao.deleteAll.flatMap(_ => ssrDao.insertAll(rows)).map { x =>
      Ok("success!")
    }
  }

  def insertFpkm = Action.async {
    val file1 = new File(parent, "gene.fpkm.mat1.txt")
    val file2 = new File(parent, "gene.fpkm.mat2.txt")
    val files = List(file1, file2)
    val rows = files.flatMap { file =>
      val buffer = FileUtils.readLines(file).asScala
      val header = buffer.take(1).flatMap(_.split("\t"))
      val rows = buffer.drop(1).flatMap { x =>
        val columns = x.split("\t")
        columns.drop(1).zipWithIndex.map {
          case (value, index) =>
            val sampleName = header(index + 1)
            val group = sampleName.replaceAll("-[^-]*$", "")
            FpkmRow(columns(0), sampleName, value.toDouble, group)
        }
      }
      rows
    }
    fpkmDao.deleteAll.flatMap(_ => fpkmDao.insertAll(rows)).map { x =>
      Ok("success!")
    }
  }

  def insertQtl = Action.async {
    val file = new File(parent, "qtl.txt")
    val lines = file.txtLines
    val rows = lines.map { columns =>
      QtlRow(0, columns(1), columns(2).toInt, columns(3).toInt, columns(4), columns(5), columns(6).toDouble,
        columns(7).toDouble, columns(8).toDouble, columns(9).toDouble)
    }
    qtlDao.deleteAll.flatMap(_ => qtlDao.insertAll(rows)).map { x =>
      Ok("success!")
    }
  }

  def insertUmami = Action.async {
    val file = new File(parent, "umami.txt")
    val lines = file.txtLines
    val rows = lines.map { columns =>
      UmamiRow(columns(0), columns(1), columns(2), columns(3), columns(4), columns(5),
        columns(6), columns(7), columns(8), columns(9), columns(10), columns(11),
        columns(12), columns(13), columns(14), columns(15), columns(16), columns(17),
        columns(18), columns(19), columns(20)
      )
    }
    //    umamiDao.deleteAll.flatMap(_ => umamiDao.insertAll(rows)).map { x =>
    //      Ok("success!")
    //    }
    umamiDao.insertAll(rows).map { x =>
      Ok("success!")
    }
  }

  def insertBitterTaste = Action.async {
    val file = new File(parent, "bittertaste.txt")
    val lines = file.txtLines
    val rows = lines.map { columns =>
      BittertasteRow(0, columns(1), columns(2), columns(3), columns(4), columns(5), columns(6))
    }
    bitterTasteDao.deleteAll.flatMap(_ => bitterTasteDao.insertAll(rows)).map { x =>
      Ok("success!")
    }
  }

  def insertGeneticMap = Action.async {
    val file = new File(parent, "geneticmap.txt")
    val lines = file.txtLines
    val rows = lines.map { columns =>
      GeneticmapRow(columns(0), columns(1).toDouble, columns(2))
    }
    geneticMapDao.deleteAll.flatMap(_ => geneticMapDao.insertAll(rows)).map { x =>
      Ok("success!")
    }
  }

  def insertUmamiSites = Action.async {
    val file = new File(parent, "umamisite.txt")
    val lines = file.txtLines
    val rows = lines.map { columns =>
      UmamisiteRow(columns(0), columns(1), columns(2).toInt, columns(3), columns(4), columns(5).toDouble, columns(6).toDouble,
        columns(7).toDouble, columns(8).toDouble, columns(9).toDouble)
    }
    umamiSiteDao.deleteAll.flatMap(_ => umamiSiteDao.insertAll(rows)).map { x =>
      Ok("success!")
    }
  }

  def insertPaper = Action.async {
    val file=new File(parent,"paper.txt")
    val lines =file.txtLines
    val rows = lines.map { columns =>
      PaperRow(columns(0), columns(1), columns(2), columns(3), columns(4))
    }
    paperDao.deleteAll.flatMap(_ => paperDao.insertAll(rows)).map { x =>
      Ok("success!")
    }
  }


  def insertBgPep = Action.async {
    val file = new File(parent, "BottleGourd.gene.pep.final")
    val buffer = FileUtils.readLines(file).asScala
    val idsBuffer = buffer.filter(_.startsWith((">")))
    val cdsBuffer = buffer.filterNot(_.startsWith((">")))
    val rows = idsBuffer.zip(cdsBuffer).map {
      case (ids, cds) =>
        val id = ids.split("\\s+")(0).replaceAll("^>", "")
        BgpepRow(id, cds)
    }
    bgPepDao.deleteAll.flatMap(_ => bgPepDao.insertAll(rows.toList)).map { x =>
      Ok("success!")
    }
  }


}
